package com.lanyou.esb.cook.proxy.service.impl;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang3.StringUtils;

import com.lanyou.esb.cook.proxy.common.Constants;
import com.lanyou.esb.cook.proxy.dao.impl.BaseDao;
import com.lanyou.esb.cook.proxy.entity.TraceLog;
import com.lanyou.esb.cook.proxy.redis.CommonUtils;
import com.lanyou.esb.cook.proxy.redis.proxy.impl.TraceLogJedisProxy;
import com.lanyou.esb.cook.proxy.redis.vo.Group;
import com.lanyou.esb.cook.proxy.redis.vo.Group.Entry;
import com.lanyou.esb.cook.proxy.service.GroupService;
import com.lanyou.esb.cook.proxy.service.Service;
import com.lanyou.esb.cook.proxy.service.TraceLogService;

/**
 * 跟踪日志服务
 * 
 * @author Davey.wu
 */
public class TraceLogServiceImpl implements TraceLogService,
		GroupService<TraceLog>, Service<TraceLog> {
	/** 数据库操作接口 **/
	private BaseDao<TraceLog> dao;
	/** 跟踪日志Redis操作代理 **/
	private TraceLogJedisProxy jedisProxy;

	/** 本地线程变量，用于保存当前线程的跟踪日志信息 **/
	private static ThreadLocal<TraceLog> THREADLOCAL_TRACELOG = new ThreadLocal<>();
	/** 是否开启跟踪日志模式 **/
	private static ThreadLocal<Boolean> THREADlOCAL_IS_TRACE = new ThreadLocal<>();
	/** 跟踪日志基本信息 **/
	private static ThreadLocal<Map<String, Object>> THREADLOCAL_BASEINFO = new ThreadLocal<>();

	/**
	 * 清理数据
	 */
	public static void clear() {
		THREADLOCAL_TRACELOG.remove();
		THREADlOCAL_IS_TRACE.remove();
		THREADLOCAL_BASEINFO.remove();
	}

	/**
	 * 添加跟踪日志基本信息
	 * 
	 * @param key
	 *            :键
	 * @param value
	 *            ：值
	 */
	public static void addBaseInfo(String key, Object value) {
		Map<String, Object> map = THREADLOCAL_BASEINFO.get();
		if (map == null) {
			map = new HashMap<>(4);
			THREADLOCAL_BASEINFO.set(map);
		}
		map.put(key, value);
	}

	/**
	 * 关闭跟踪日志模式
	 */
	public static void closeTrace() {
		THREADlOCAL_IS_TRACE.remove();
	}

	/**
	 * 开启跟踪日志模式
	 */
	public static void openTrace() {
		THREADlOCAL_IS_TRACE.set(true);
	}

	/**
	 * 判断是否开启日志跟踪模式
	 * 
	 * @return
	 */
	public static boolean isTrace() {
		if (THREADlOCAL_IS_TRACE.get() != null
				&& true == THREADlOCAL_IS_TRACE.get()) {
			return true;
		}
		return false;
	}

	/**
	 * 增加跟踪日志
	 * 
	 * @param members
	 *            ：消息列表
	 */
	public static void addTraceLog(String... members) {
		if (members == null || members.length == 0) {
			return;
		}

		TraceLog log = THREADLOCAL_TRACELOG.get();
		if (log == null) {
			// 不存在跟踪队列，添加
			log = TraceLog.getInstance();
			THREADLOCAL_TRACELOG.set(log);
		}
		if (members.length == 1) {
			log.appendMsg(members[0]);
			return;
		}
		StringBuilder builder = new StringBuilder();
		// 合并消息列表
		for (String member : members) {
			builder.append(member);
		}

		log.appendMsg(builder.toString());
	}

	@Override
	public TraceLog getLog() {
		// 获取当前线程的跟踪日志
		TraceLog log = THREADLOCAL_TRACELOG.get();
		if (log == null) {
			return null;
		}
		Map<String, Object> map = THREADLOCAL_BASEINFO.get();
		if (map == null) {
			return log;
		}
		// 设置跟踪日志基本信息
		String ifId = (String) map.get(Constants.IF_ID_KEY);
		String callSystemCode = (String) map.get(Constants.CALLSYSTEMCODE_KEY);
		String creator = (String) map.get(Constants.CREATOR_KEY);
		if (StringUtils.isNotBlank(ifId)) {
			log.setIfId(ifId);
		}
		if (StringUtils.isNotBlank(callSystemCode)) {
			log.setCallSystemCode(callSystemCode);
		}
		if (StringUtils.isNotBlank(creator)) {
			log.setCreator(creator);
			log.setModifier(creator);
		}

		return log;
	}

	@Override
	public Group getGroup(TraceLog log) {
		if (log == null) {
			return null;
		}
		String json = "";
		try {
			json = CommonUtils.toJson(log);
		} catch (Exception e) {
			return null;
		}
		Group group = new Group();
		// list类型条件集合
		List<Entry> lists = new ArrayList<>(1);
		group.setLists(lists);

		Entry entry = new Entry();
		entry.setKey(jedisProxy.getKey());
		entry.setValue(json);
		lists.add(entry);
		return group;
	}

	@Override
	public void pushToRedis() {
		// 判断是否开启跟踪日志模式
		if (!TraceLogServiceImpl.isTrace()) {
			return;
		}
		// 获取当前线程的跟踪日志
		TraceLog log = getLog();
		if (log == null) {
			return;
		}
		try {
			// 将跟踪信息存入REDIS
			jedisProxy.rpush(jedisProxy.getKey(), log);
		} catch (Exception e) {
			e.printStackTrace();
		}
		// 清理数据
		clear();
	}

	@Override
	public void save(List<TraceLog> list) throws Exception {
		if (list == null || list.isEmpty()) {
			return;
		}
		// 保存跟踪日志到数据库
		this.dao.saveAll(list);
	}

	@Override
	public void update(List<TraceLog> list) throws Exception {
		// 跟踪日志目前不存在更新业务，所以不提供实现
	}

	public TraceLogJedisProxy getJedisProxy() {
		return jedisProxy;
	}

	public void setJedisProxy(TraceLogJedisProxy jedisProxy) {
		this.jedisProxy = jedisProxy;
	}

	public BaseDao<TraceLog> getDao() {
		return dao;
	}

	public void setDao(BaseDao<TraceLog> dao) {
		this.dao = dao;
	}

}
